/**
 * Copyright (C), 2020, JieYi Software System Co., Ltd.
 * All rights reserved.
 * FileName:       LoginService.java
 *
 * @Description:
 * @author: feiwe
 * Modification History:
 * Date         Author        Version        Discription
 * -------------------------------------------------------
 * 2020/11/16      feiwe                         add
 */


package com.fengwei.service;

import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.util.StrUtil;
import com.fengwei.dao.MdmsUserMapper;
import com.fengwei.form.MdmsUser;
import com.fengwei.requestdata.login.LoginBindGoogleAuthData;
import com.fengwei.requestdata.login.LoginData;
import com.fengwei.requestdata.login.LoginGoogleAuthData;
import com.fengwei.util.GoogleAuthenticator;
import com.fengwei.util.HexStringUtil;
import com.fengwei.util.MdmsConsts;
import com.fengwei.util.PltResult;
import com.fengwei.util.RSAAssistUtil;
import com.fengwei.util.RSAUtil;
import com.fengwei.util.VerifyException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap;
import java.util.Map;

@Service
public class LoginService {
    private final static Logger logger = LoggerFactory.getLogger(LoginService.class);

    @Autowired
    private MdmsUserMapper mdmsUserMapper;

    @Autowired
    private Map springSecurityUserTypeMap;

    public Map<String, Object> getOtp(HttpServletRequest request) throws Exception {
        Map<String, Object> returnData = new HashMap<>();
        String otpcode = ObjectId.next();
        logger.info("otpcode:" + otpcode);
        String[] rsaKeyPair = RSAAssistUtil.getKeyStringPair(512);
        HttpSession session = request.getSession();
        logger.debug("session.getId():" + session.getId());
        session.setAttribute(otpcode, rsaKeyPair);

        returnData.put("otpcode", otpcode);
        returnData.put("otp", rsaKeyPair[0]);
        return returnData;
    }

    public Map<String, Object> login(LoginData loginData, HttpServletRequest request) throws Exception {
        Map<String, Object> returnData = new HashMap<>();
        HttpSession session = request.getSession();
        logger.debug("session.getId():" + session.getId());

        Map mapSelectByUserCode = new HashMap();
        mapSelectByUserCode.put("userCode", loginData.getUserCode());

        String[] rsaKeyPair = (String[]) session.getAttribute(loginData.getOtpCode());
        session.removeAttribute(loginData.getOtpCode());
        String modulus = rsaKeyPair[0];
        String exponentPri = rsaKeyPair[1];
        RSAPrivateKey rsaPrivateKey = RSAUtil.loadPrivateKey(modulus, exponentPri, 16);
        byte[] plainText = RSAUtil.privateKeyDecrypt("RSA", "ECB", "PKCS1Padding", rsaPrivateKey, HexStringUtil.hexStringToBytes(loginData.getUserPassword()));
        String password = new String(plainText);
        logger.info("password:" + password);

        MdmsUser mdmsUser = mdmsUserMapper.selectByUserCode(mapSelectByUserCode);
        if (null == mdmsUser) {
            logger.error("用户不存在");
            throw new VerifyException(PltResult.RESULT_CF003);
        } else if (!MdmsConsts.USER_STATUS_0.equals(mdmsUser.getUserStatus())) {
            logger.error("用户状态非法");
            throw new VerifyException(PltResult.RESULT_CF004);
        } else {
            if (!password.equals(mdmsUser.getUserPassword())) {
                logger.error("密码错误");
                throw new VerifyException(PltResult.RESULT_CF003);
            } else {
                if (MdmsConsts.MFA_FLAG_0.equals(mdmsUser.getMfaFlag())) {
                    returnData.put("action", MdmsConsts.ACTION_AFT_AUTHUSER_LOGIN_0);

                    //SpringSecurity用户对应角色的设置
                    springSecurityUserTypeMap.put(mdmsUser.getUserCode(), mdmsUser.getUserType());
                    returnData.put("userName", mdmsUser.getUserCode());

                    session.setAttribute("mdmsUser", mdmsUser);
                } else if (MdmsConsts.MFA_FLAG_1.equals(mdmsUser.getMfaFlag())) {
                    if (StrUtil.hasEmpty(mdmsUser.getMfaSecret())) {
                        returnData.put("action", MdmsConsts.ACTION_AFT_AUTHUSER_LOGIN_10);
                        //Google密钥
                        String randomSecretKey = GoogleAuthenticator.getRandomSecretKey();
                        logger.info("randomSecretKey:" + randomSecretKey);

                        String googleAuthenticatorBarCode = GoogleAuthenticator.getGoogleAuthenticatorBarCode(randomSecretKey, mdmsUser.getUserCode(),
                                "mdms");
                        logger.info("googleAuthenticatorBarCode:" + googleAuthenticatorBarCode);
                        String googleAuthenticatorBarCodeImgBase64 = GoogleAuthenticator.createQRCodeImgBase64(googleAuthenticatorBarCode, 200, 200);

                        returnData.put("userid", mdmsUser.getId() + "");
                        returnData.put("googleauthenticatorbarcode", googleAuthenticatorBarCodeImgBase64);
                        session.setAttribute("googlesecret" + mdmsUser.getId(), randomSecretKey);
                    } else {
                        returnData.put("action", MdmsConsts.ACTION_AFT_AUTHUSER_LOGIN_11);
                        //先放在临时里面，等校验过了就从临时取到正式
                        session.setAttribute("mdmsUserTemp", mdmsUser);
                    }
                } else if (MdmsConsts.MFA_FLAG_2.equals(mdmsUser.getMfaFlag())) {
                    returnData.put("action", MdmsConsts.ACTION_AFT_AUTHUSER_LOGIN_2);
                    //TODO:短信认证，待完善
                } else {
                    throw new VerifyException(PltResult.RESULT_CF030);
                }
            }
        }

        return returnData;
    }

    public Map<String, Object> bindGoogleAuth(LoginBindGoogleAuthData loginBindGoogleAuthData, HttpServletRequest request) {
        Map<String, Object> returnData = new HashMap<>();
        HttpSession session = request.getSession();
        String randomSecretKey = (String) session.getAttribute("googlesecret" + loginBindGoogleAuthData.getUserid());
        if (StrUtil.hasEmpty(randomSecretKey)) {
            throw new VerifyException(PltResult.RESULT_CF031);
        }

        boolean isTrue = GoogleAuthenticator.checkCode(randomSecretKey, Long.parseLong(loginBindGoogleAuthData.getOtp()), System.currentTimeMillis());
        if (!isTrue) {
            throw new VerifyException(PltResult.RESULT_CF032);
        }

        Map mapUpdate = new HashMap();
        mapUpdate.put("id", loginBindGoogleAuthData.getUserid());
        mapUpdate.put("mfaSecret", randomSecretKey);
        int iRet = mdmsUserMapper.update(mapUpdate);

        if (iRet == 0) {
            throw new VerifyException(PltResult.RESULT_CF017);
        }

        return returnData;
    }

    public Map<String, Object> googleAuth(LoginGoogleAuthData loginGoogleAuthData, HttpServletRequest request) {
        Map<String, Object> returnData = new HashMap<>();
        HttpSession session = request.getSession();
        MdmsUser mdmsUser = (MdmsUser) session.getAttribute("mdmsUserTemp");

        /*判断是不是可以继续尝试*/
        String nextTimeStr = (String) session.getAttribute("wrongTimeGap" + mdmsUser.getId());
        if (!StrUtil.hasEmpty(nextTimeStr)) {
            long nextTime = Long.parseLong(nextTimeStr);
            if (System.currentTimeMillis() <= nextTime) {
                throw new VerifyException(PltResult.RESULT_CF989);
            }
        }

        /*验证*/
        boolean isTrue = GoogleAuthenticator.checkCode(mdmsUser.getMfaSecret(), Long.parseLong(loginGoogleAuthData.getOtp()), System.currentTimeMillis());
        if (!isTrue) {
            session.setAttribute("wrongTimeGap" + mdmsUser.getId(), (System.currentTimeMillis() + 5000) + "");
            VerifyException verifyException = new VerifyException(PltResult.RESULT_CF032);
            verifyException.setErrorDesc(PltResult.RESULT_CF032.getpName() + "，请5秒后再试");
            throw verifyException;
        }

        //SpringSecurity用户对应角色的设置
        springSecurityUserTypeMap.put(mdmsUser.getUserCode(), mdmsUser.getUserType());
        returnData.put("userName", mdmsUser.getUserCode());

        session.removeAttribute("mdmsUserTemp");
        session.setAttribute("mdmsUser", mdmsUser);

        return returnData;
    }
}
